/**
 * Author: ling
 * Create Time: 2018-12-03 15:45
 * Description: 发布-订阅模式/观察者模式
 */
salesOffices = {};
salesOffices.clientList = [];

salesOffices.listen = function (key, fn) {
  if (!this.clientList[key]) {
    this.clientList[key] = []
  }
  this.clientList[key].push(fn)
};
salesOffices.trigger = function () {
  let key = Array.prototype.shift.apply(arguments),
    fns = this.clientList[key];

  if (!fns || !fns.length) {
    return false
  }

  for (let fn of fns) {
    fn.apply(this, arguments)
  }
};

salesOffices.listen('90平米', function (price) {
  console.log(price)
});
salesOffices.listen('100平米', function (price) {
  console.log(price)
});

salesOffices.trigger("90平米", "100万");
salesOffices.trigger("100平米", "120万");


// 通用实现
event = {
  clientList: {},
  listen: function (key, fn) {
    if (!this.clientList[key]) {
      this.clientList[key] = []
    }
    this.clientList[key].push(fn)
  },
  remove: function (key, fn) {
    let fns = this.clientList[key];
    if (!fns || !fns.length) {
      return false
    }

    for (let l = fns.length - 1; l >= 0; l--) {
      let _fn = fns[l];
      if (_fn === fn) {
        fns.splice(l, 1)
      }
    }
  },
  trigger: function () {
    let key = Array.prototype.shift.apply(arguments),
      fns = this.clientList[key];

    if (!fns || !fns.length) {
      return false
    }

    for (let fn of fns) {
      fn.apply(this, arguments)
    }
  }
};

installEvent = function (obj) {
  for (let i in event) {
    obj[i] = event[i]
  }
};

salesOffices2 = {};
installEvent(salesOffices2);
salesOffices2.listen('900平米', fn1 = function (price) {
  console.log(price)
});
salesOffices2.listen('900平米', fn2 = function (price) {
  console.log(price)
});
salesOffices2.listen('1000平米', function (price) {
  console.log(price)
});

salesOffices2.trigger("900平米", "10000万");
salesOffices2.trigger("1000平米", "12000万");
salesOffices2.remove('900平米', fn2);
salesOffices2.trigger("900平米", "10000万");

// 最终实现方式
LingEvent = (function () {

  return (function () {
    let namespaceCache = {};

    let each = function (arr, fn) {
      let ret;
      for (let i = 0, len = arr.length; i < len; i++) {
        ret = fn.call(arr[i], i, arr[i])
      }
      return ret
    };

    let _listen = function (key, fn, cache) {
      if (!cache[key]) {
        cache[key] = []
      }
      cache[key].push(fn)
    };

    let _remove = function (key, cache, fn) {
      if (cache[key]) {
        if (fn) {
          for (let i = cache[key].length; i >= 0; i--) {
            if (cache[key][i] === fn) {
              cache[key].splice(i, 1)
            }
          }
        } else {
          cache[key] = []
        }
      }
    };

    let _trigger = function () {
      let cache = Array.prototype.shift.call(arguments),
        key = Array.prototype.shift.call(arguments),
        args = arguments,
        _this = this,
        fns = cache[key];

      if (!fns || !fns.length) {
        return false
      }

      return each(fns, function () {
        return this.apply(_this, args)
      })
    };

    let _create = function (namespace = 'default') {
      let cache = {},
        offlineStack = [],
        ret = {
          listen: function (key, fn, last) {
            _listen(key, fn, cache);

            if (offlineStack === null) {
              return false
            }

            if (last === 'last') {
              offlineStack.length && offlineStack.pop()();
            } else {
              each(offlineStack, function () {
                this()
              })
            }
            offlineStack = null
          },
          one: function (key, fn, last) {
            _remove(key, cache);
            this.listen(key, fn, last)
          },
          remove: function (key, fn) {
            _remove(key, cache, fn)
          },
          trigger: function () {
            let fn,
              args,
              _this = this;

            Array.prototype.unshift.call(arguments, cache);
            args = arguments;

            fn = function () {
              return _trigger.apply(_this, args)
            };

            if (offlineStack) {
              return offlineStack.push(fn)
            }

            return fn()
          }
        };

      return namespace ? namespaceCache[namespace]
        ? namespaceCache[namespace] : namespaceCache[namespace] = ret
        : ret
    };

    return {
      create: _create,
      one: function (key, fn, last) {
        let event = this.create();
        event.one(key, fn, last)
      },
      remove: function (key, fn) {
        let event = this.create();
        event.remove(key, fn)
      },
      listen: function (key, fn, last) {
        let event = this.create();
        event.listen(key, fn, last)
      },
      trigger: function () {
        let event = this.create();
        event.trigger.apply(this, arguments)
      }
    }
  })();
})();

LingEvent.create('ling').listen('click', function () {
  console.log('click')
});
LingEvent.create('ling').trigger('click');
LingEvent.listen('click', function () {
  console.log('......')
});
LingEvent.trigger('click');
